package org.xmap.app;

import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Font;
import java.util.Calendar;
import java.util.TimeZone;
import org.xmap.ui.ViewManager;

/**
 * <p>应用程序环境类，定义了一些全局变量，在初始化的时候还会根据环境做一些动态的计算。</p>
 * <p>在Xmap里面，左软键和右软键主要用在菜单响应上，左软键用于选择左侧的菜单或确认，右软键用于选择右侧的菜单或返回。之所以要定义两套键值，是为了方便某些机器上，可以两个按键实现同一个功能，比如右软键和删除键可以同时响应右侧菜单。</p>
 * @author Zealot
 * @version 1.0
 */
public final class Env {

    /**
     * 全局环境实例。
     */
    public static final Env instance = new Env();
    /**
     * 调试开关，当打开的时候，可以输出调试信息，程序中按井键可以切换到调试界面，在最终版本的时候，要把调试开关关闭。
     */
    public final boolean debug = true;
    /**
     * 标志是否是首次调用startApp。
     */
    public boolean startAtFirstTime = false;
    /**
     * 屏幕的宽度，这个值会动态变化，比如在N95这类机器上，用户可以通过滑盖来切换屏幕为横屏或竖屏，系统会动态检测这种变化。
     */
    public int screenWidth = 0;
    /**
     * 屏幕的高度，这个值会动态变化，比如在N95这类机器上，用户可以通过滑盖来切换屏幕为横屏或竖屏，系统会动态检测这种变化。
     */
    public int screenHeight = 0;
    /**
     * 是否支持触笔事件。
     */
    public boolean hasPointerEvents = false;
    /**
     * 左软键的键值一。
     */
    public int leftSoftKey = -6;
    /**
     * 左软键的键值二
     */
    public int leftSoftKeySnd = -21;
    /**
     * 右软键的键值一。
     */
    public int rightSoftKey = -7;
    /**
     * 右软键的键值二。
     */
    public int rightSoftKeySnd = -22;
    /**
     * 视图管理器的更新周期，单位为毫秒。
     */
    public int updateCycle = 50;
    /**
     * 首次按键按下到响应REPEATED事件的时间，单位为毫秒。
     */
    public final int firstRepeatedInterval = 800;
    /**
     * 按键重复的延迟，单位为毫秒。
     */
    public final int keyRepeatedInterval = 30;
    /**
     * 默认的字体，系统的最小号的字体。
     */
    public Font defaultFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL);
    /**
     * 该字体的高度是经过调整的高度，有些手机的字体距离顶部和底部距离太小，排版后行之间没有间隔，不够美观。这个高度是调整过的，对于过密的字体，加大了行间距，使排版后的字体变得美观。
     */
    public int defaultFontHeight = 0;
    /**
     * 默认的字体在纵坐标上的偏移，这个偏移是字体距离顶部和底部的距离的一半，因为每个设备的字体都不一样，计算这个值，可以方便字体居中绘制。
     */
    public int defaultFontYOffset = 0;
    /**
     * 文字顶部的空白象素数。
     */
    public int topLine = 0;
    /**
     * 文字底部的空白象素数。
     */
    public int bottomLine = 0;
    /**
     * 字符串格式的时间。
     */
    public String strTime = Env.getTime();
    /**
     * 最近一次更新时间的毫秒数。
     */
    public long lastCheckTime = System.currentTimeMillis();

    /**
     * 私有的构造函数，不允许生成实例。
     */
    private Env() {
        this.resetFont(this.defaultFont);
    }

    /**
     * 重新设置字体，并根据新的字体计算变量的值。
     * @param f 新的字体。
     */
    public void resetFont(Font f) {
        this.defaultFont = f;
        this.defaultFontHeight = this.defaultFont.getHeight();
        this.topLine = 0;
        this.bottomLine = 0;
        Image fontImage = Image.createImage(50, this.defaultFontHeight);
        Graphics g = fontImage.getGraphics();
        g.setColor(0xffffffff);
        g.fillRect(0, 0, fontImage.getWidth(), fontImage.getHeight());
        g.setColor(0xff000000);
        g.setFont(this.defaultFont);
        g.drawString("退出", 0, 0, Graphics.LEFT | Graphics.TOP); // 选中"退出"作为测试例子
        int[] data = new int[fontImage.getWidth() * fontImage.getHeight()];
        fontImage.getRGB(data, 0, fontImage.getWidth(), 0, 0, fontImage.getWidth(), fontImage.getHeight());
        for (int i = 0; i < data.length; i += fontImage.getWidth()) {
            boolean blankLine = true;
            for (int j = 0; j < fontImage.getWidth(); j++) {
                if (data[i + j] != -1) {
                    blankLine = false;
                    break;
                }
            }
            if (blankLine) {
                this.topLine++;
            } else {
                break;
            }
        }
        for (int i = data.length - 1; i >= fontImage.getWidth() - 1; i -= fontImage.getWidth()) {
            boolean blankLine = true;
            for (int j = 0; j < fontImage.getWidth(); j++) {
                if (data[i - j] != -1) {
                    blankLine = false;
                    break;
                }
            }
            if (blankLine) {
                this.bottomLine++;
            } else {
                break;
            }
        }
        int maxTopBottom = Math.max(this.topLine, this.bottomLine);
        if (maxTopBottom < 2) {
            maxTopBottom = 2;
        }
        this.defaultFontYOffset = maxTopBottom - this.topLine;
        this.defaultFontHeight = this.defaultFontHeight + (maxTopBottom << 1) - this.topLine - this.bottomLine;
    }

    /**
     * 更新时间字符串。
     */
    public void updateTime() {
        if (System.currentTimeMillis() - this.lastCheckTime > 30000) {
            this.strTime = Env.getTime();
            this.lastCheckTime = System.currentTimeMillis();
            ViewManager.instance.requestRepaint();
        }
    }

    /**
     * 获取时间。
     * @return 字符串格式的时间。
     */
    public static String getTime() {
        TimeZone tz = TimeZone.getDefault();
        Calendar ca = Calendar.getInstance(tz);
        String strHour = String.valueOf(ca.get(Calendar.HOUR_OF_DAY)) + ":";
        String strMin = String.valueOf(ca.get(Calendar.MINUTE));
        if (ca.get(Calendar.HOUR_OF_DAY) <= 9) {
            strHour = "0" + strHour;
        }
        if (ca.get(Calendar.MINUTE) <= 9) {
            strMin = "0" + strMin;
        }
        return strHour + strMin;
    }
}
